package com.codeczx.rockerviewdemo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

/**
 * Created by codeczx on 2017/7/21.
 */

public class RockerView extends View {

    private static final String TAG = "RockerView";
    private Paint backgroundPaint;
    private Paint rockerPaint;
    private int rockerX;
    private int rockerY;
    private int rockerRadius = 100;
    private int defaultSize = 400;
    private int maxAvaliable;
    private int lastX = 0;
    private int lastY = 0;

    public RockerView(Context context) {
        this(context, null);
    }

    public RockerView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RockerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        backgroundPaint = new Paint();
        backgroundPaint.setColor(Color.BLUE);
        backgroundPaint.setStyle(Paint.Style.FILL);

        rockerPaint = new Paint();
        rockerPaint.setColor(Color.RED);
        rockerPaint.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
    }

    private int measureWidth(int widthMeasureSpec) {
        int specSize = MeasureSpec.getSize(widthMeasureSpec);
        int specMode = MeasureSpec.getMode(widthMeasureSpec);


        int width = 0;

        switch (specMode) {
            case MeasureSpec.EXACTLY:
                width = specSize;
                break;
            case MeasureSpec.AT_MOST:
                width = Math.min(specSize, defaultSize);
                break;
        }
        rockerX = width / 2;
        return width;
    }

    private int measureHeight(int heightMeasureSpec) {
        int specSize = MeasureSpec.getSize(heightMeasureSpec);
        int specMode = MeasureSpec.getMode(heightMeasureSpec);

        int height = 0;

        switch (specMode) {
            case MeasureSpec.EXACTLY:
                height = specSize;
                break;
            case MeasureSpec.AT_MOST:
                height = Math.min(specSize, defaultSize);
                break;
        }
        rockerY = height / 2;
        return height;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        canvas.drawCircle(width / 2, height / 2, width / 2, backgroundPaint);
        canvas.drawCircle(rockerX, rockerY, rockerRadius, rockerPaint);
    }

    private int translateCoordinateXBefore(int x) {
        if (x < getMeasuredWidth() / 2) {
            x = -(getMeasuredWidth() / 2 - x);
        }
        if (x > getMeasuredWidth() / 2) {
            x = x - getMeasuredWidth() / 2;
        }
        return x;
    }

    private int translateCoordinateYBefore(int y) {
        y = getMeasuredWidth() / 2 - y;
        return y;
    }

    private int translateCoordinateXAfter(int x) {
        if (x < 0) {
            x = getMeasuredWidth() / 2 + x;
        } else {
            x += getMeasuredWidth() / 2;
        }
        return x;
    }

    private int translateCoordinateYAfter(int y) {
        y = getMeasuredHeight() / 2 - y;
        return y;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                Log.i(TAG, "onTouchEvent: " + x + " " + y);
                int offset = 10;
                if (Math.abs(lastX - x) < offset || Math.abs(lastY - y) < offset) {
                    return true;
                }
                int tempX = x;
                int tempY = y;

                tempX = translateCoordinateXBefore(tempX);
                tempY = translateCoordinateYBefore(tempY);

                int resultX;
                int resultY;
                int saveSign = tempX / Math.abs(tempX);

                maxAvaliable = (int) Math.sqrt(Math.pow((getMeasuredWidth() / 2 - rockerRadius), 2));
                if (Math.pow(tempX, 2) + Math.pow(tempY, 2) > Math.pow(maxAvaliable, 2)) {
                    float k = (float) tempY / (float) tempX;
                    resultX = (int) Math.sqrt((Math.pow(maxAvaliable, 2) / (1 + Math.pow(k, 2))));
                    resultX = resultX * saveSign;
                    resultY = (int) (resultX * k);
                    rockerX = translateCoordinateXAfter(resultX);
                    rockerY = translateCoordinateYAfter(resultY);
                } else {
                    rockerX = x;
                    rockerY = y;
                }
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                rockerX = getMeasuredWidth() / 2;
                rockerY = getMeasuredHeight() / 2;
                invalidate();
                break;
        }
        lastX = x;
        lastY = y;
        return true;
    }
}
